#include "tuya_hal_gpio.h"

#include "app_common.h"
#include "tal_log.h"
#include "tal_memory.h"

//******************************************************************************
//                              led op api                                     *
//******************************************************************************
TIMER_ID etimer_blink_sw;
led_operate_t *g_led_operate = NULL;
UINT8_T g_led_sum;
BOOL_T g_led_timer_is_create = FALSE;
/**
 * @note led gpio output initialize
 * @param[in] {led_config} config information
 * @param[in] {led_sum} no=umbers of output gpio information
 * @return none
 */
VOID_T tal_led_gpio_init(led_config_t *led_config, UINT8_T led_sum)
{
  if (!led_sum)
  {
    return;
  }
  else
  {
    g_led_sum = led_sum;
  }

  g_led_operate = tal_malloc(sizeof(led_operate_t) * g_led_sum);
  if (g_led_operate == NULL)
  {
    return;
  }
  tal_system_memset(g_led_operate, 0, sizeof(led_operate_t) * g_led_sum);
  for (UINT8_T i = 0; i < g_led_sum; ++i)
  {
    TUYA_GPIO_BASE_CFG_T led_gpio_cfg = {
        .mode = TUYA_GPIO_PUSH_PULL,
        .direct = TUYA_GPIO_OUTPUT};
    if ((LED_ST_T)led_config[i].led_active_level == led_config[i].led_init_st)
    {
      led_gpio_cfg.level = TUYA_GPIO_LEVEL_HIGH;
    }
    else
    {
      led_gpio_cfg.level = TUYA_GPIO_LEVEL_LOW;
    }

    tal_gpio_init(led_config[i].led_pin_num, &led_gpio_cfg);
    g_led_operate[i].led_pin_num = led_config[i].led_pin_num;
    g_led_operate[i].led_active_level = led_config[i].led_active_level;
  }
}

/**
 * @note device output(led) blink start funciton
 * @param[in] {led_pin_num} led gpio num
 * @param[in] {on_time} led on time
 * @param[in] {off_time} led off time
 * @param[in] {blink_times} blink times
 * @param[in] {end_st} end state, end with on or off
 * @return none
 */
VOID_T tal_led_start_blink(TUYA_GPIO_NUM_E led_pin_num, UINT32_T on_time, UINT32_T off_time, UINT16_T blink_times, LED_ST_T end_st)
{
  if (end_st < 0 || !blink_times || !(on_time || off_time))
  {
    return;
  }

  for (UINT8_T i = 0; i < g_led_sum; ++i)
  {
    if (g_led_operate[i].led_pin_num == led_pin_num)
    {
      g_led_operate[i].on_time = on_time;
      g_led_operate[i].off_time = off_time;
      g_led_operate[i].blink_times = blink_times;
      g_led_operate[i].end_st = end_st;
      g_led_operate[i].is_start = TRUE;
      g_led_operate[i].count = 0;
      break;
    }
  }

  if (!g_led_timer_is_create)
  {
    tal_sw_timer_create(app_led_blink_timer_cb, NULL, &etimer_blink_sw);
    g_led_timer_is_create = TRUE;
  }

  if (!tal_sw_timer_is_running(etimer_blink_sw))
  {
    tal_sw_timer_start(etimer_blink_sw, 10, TAL_TIMER_CYCLE);
  }
}

/**
 * @brief
 *
 * @param timer_id
 * @param arg
 * @return VOID_T
 */
VOID_T app_led_blink_timer_cb(TIMER_ID timer_id, VOID_T *arg)
{
  UINT8_T end_count = 0;

  for (UINT8_T i = 0; i < g_led_sum; ++i)
  {
    if (!g_led_operate[i].is_start)
    {
      end_count++;
      if (end_count == g_led_sum)
      {
        tal_sw_timer_stop(etimer_blink_sw);
      }
      continue;
    }

    if (g_led_operate[i].count >= g_led_operate[i].off_time / 10 + g_led_operate[i].on_time / 10)
    {
      g_led_operate[i].count = 0;
      g_led_operate[i].blink_times--;
      if (!g_led_operate[i].blink_times)
      {
        g_led_operate[i].on_time = 0;
        g_led_operate[i].off_time = 0;
        g_led_operate[i].blink_times = 0;
        g_led_operate[i].is_start = FALSE;
        g_led_operate[i].count = 0;
        if ((LED_ST_T)g_led_operate[i].led_active_level == g_led_operate[i].end_st)
        {
          tal_gpio_write(g_led_operate[i].led_pin_num, TUYA_GPIO_LEVEL_HIGH);
        }
        else
        {
          tal_gpio_write(g_led_operate[i].led_pin_num, TUYA_GPIO_LEVEL_LOW);
        }
      }
    }

    if (g_led_operate[i].count < g_led_operate[i].on_time / 10)
    {
      if (g_led_operate[i].led_active_level)
      {
        tal_gpio_write(g_led_operate[i].led_pin_num, TUYA_GPIO_LEVEL_HIGH);
      }
      else
      {
        tal_gpio_write(g_led_operate[i].led_pin_num, TUYA_GPIO_LEVEL_LOW);
      }
    }

    if ((g_led_operate[i].count >= g_led_operate[i].on_time / 10) && (g_led_operate[i].count < g_led_operate[i].off_time / 10 + g_led_operate[i].on_time / 10))
    {
      if (g_led_operate[i].led_active_level)
      {
        tal_gpio_write(g_led_operate[i].led_pin_num, TUYA_GPIO_LEVEL_LOW);
      }
      else
      {
        tal_gpio_write(g_led_operate[i].led_pin_num, TUYA_GPIO_LEVEL_HIGH);
      }
    }

    g_led_operate[i].count++;
  }
}

/**
 * @note device output(led) blink stop function
 * @param[in] {led_index} led id
 * @param[in] {end_st} end state, -1:toggle(only No blinking is available),0:off,1:on
 * @return none
 */
VOID_T tal_led_stop_blink(TUYA_GPIO_NUM_E led_pin_num, LED_ST_T end_st)
{
  for (UINT8_T i = 0; i < g_led_sum; ++i)
  {
    if (g_led_operate[i].led_pin_num == led_pin_num)
    {
      if (end_st < 0 && g_led_operate[i].is_start)
      {
        return;
      }
      g_led_operate[i].on_time = 0;
      g_led_operate[i].off_time = 0;
      g_led_operate[i].blink_times = 0;
      g_led_operate[i].end_st = end_st;
      g_led_operate[i].is_start = FALSE;
      g_led_operate[i].count = 0;

      if (end_st >= 0)
      {
        if ((LED_ST_T)g_led_operate[i].led_active_level == end_st)
        {
          tal_gpio_write(led_pin_num, TUYA_GPIO_LEVEL_HIGH);
        }
        else
        {
          tal_gpio_write(led_pin_num, TUYA_GPIO_LEVEL_LOW);
        }
      }
      else
      {
        TUYA_GPIO_LEVEL_E level = TUYA_GPIO_LEVEL_LOW;
        tal_gpio_read(led_pin_num, &level);
        if (level == TUYA_GPIO_LEVEL_LOW)
        {
          tal_gpio_write(led_pin_num, TUYA_GPIO_LEVEL_HIGH);
        }
        else
        {
          tal_gpio_write(led_pin_num, TUYA_GPIO_LEVEL_LOW);
        }
      }
      break;
    }
  }
}

/**
 * @note device led is blink or not
 * @param[in] {led_index} led id
 * @return 0 is not blink, 1 is blink
 */
BOOL_T tal_led_is_blink(TUYA_GPIO_NUM_E led_pin_num)
{
  for (UINT8_T i = 0; i < g_led_sum; ++i)
  {
    if (g_led_operate[i].led_pin_num == led_pin_num)
    {
      return g_led_operate[i].is_start;
    }
  }
  return FALSE;
}

//******************************************************************************
//                              key op api                                     *
//******************************************************************************
UINT8_T g_key_sum;
key_operate_t *g_key_operate = NULL;
key_func_t g_key_func = NULL;
UINT32_T g_debounce_time = 30;
/**
 * @note gpio output initialize
 * @param[in] {key_config} config information
 * @param[in] {key_sum} no=umbers of output gpio information
 * @param[in] {debounce_time} key debounce time
 * @param[in] {key_func} key ISR handle callback
 * @return none
 * @return none
 */
VOID_T tal_key_gpio_init(key_config_t *key_config, UINT8_T key_sum, UINT32_T debounce_time, key_func_t key_func)
{
  if (!key_sum)
  {
    return;
  }
  else
  {
    g_key_sum = key_sum;
  }

  TAL_PR_NOTICE("key_sum:%d", key_sum);
  TAL_PR_NOTICE("g_key_sum:%d", g_key_sum);
  g_key_func = key_func;
  g_debounce_time = debounce_time;
  g_key_operate = tal_malloc(sizeof(key_operate_t) * key_sum); // CHANNEL_MAX);
  if (g_key_operate == NULL)
  {
    return;
  }
  tal_system_memset(g_key_operate, 0, sizeof(key_operate_t) * g_key_sum);
  for (UINT8_T i = 0; i < g_key_sum; ++i)
  {
    TIMER_ID *etimer_key_scan = tal_malloc(sizeof(TIMER_ID));
    if (etimer_key_scan == NULL)
    {
      return;
    }
    g_key_operate[i].key_index = i;
    g_key_operate[i].pin_num = key_config[i].pin_num;
    g_key_operate[i].pin_irq_mode = key_config[i].pin_irq_mode;
    g_key_operate[i].timer = etimer_key_scan;

    TAL_PR_INFO("pin:%d(%d)timer create", g_key_operate[i].pin_num, etimer_key_scan);

    tal_sw_timer_create(app_button_scan_cb, &g_key_operate[i], g_key_operate[i].timer);
    TAL_PR_NOTICE("g_key_operate[%d].pin_irq_mode:%d, g_key_operate[i].pin_num:%d", i, g_key_operate[i].pin_irq_mode, g_key_operate[i].pin_num);
    TUYA_GPIO_IRQ_T key_gpio_cfg = {
        .mode = g_key_operate[i].pin_irq_mode,
        .cb = app_key_push_timer_cb,
        .arg = &g_key_operate[i].pin_num,
    };
    tal_gpio_irq_init(g_key_operate[i].pin_num, &key_gpio_cfg);
  }
}

// VOID_T tal_ext_key_gpio_init(ext_key_config_t *key_config, UINT32_T debounce_time, key_func_t key_func)
// {
//   g_key_sum = key_config->channel - 1;

//   g_key_func = key_func;
//   g_debounce_time = debounce_time;
//   tal_system_memset(g_key_operate, 0, sizeof(key_operate_t));
//   TIMER_ID *etimer_key_scan = tal_malloc(sizeof(TIMER_ID));
//   if (etimer_key_scan == NULL)
//   {
//     return;
//   }
//   g_key_operate[key_config->channel].key_index = key_config->channel - 1;
//   g_key_operate[key_config->channel].pin_num = key_config[0].pin_num;
//   g_key_operate[key_config->channel].pin_irq_mode = key_config[0].pin_irq_mode;
//   g_key_operate[key_config->channel].timer = etimer_key_scan;

//   TAL_PR_INFO("pin:%d(%d)timer create", g_key_operate[key_config->channel].pin_num, etimer_key_scan);

//   tal_sw_timer_create(app_button_scan_cb, &g_key_operate[key_config->channel], g_key_operate[key_config->channel].timer);

//   TUYA_GPIO_IRQ_T key_gpio_cfg = {
//       .mode = g_key_operate[key_config->channel].pin_irq_mode,
//       .cb = app_ext_key_push_timer_cb,
//       .arg = &g_key_operate[key_config->channel].pin_num,
//   };
//   tal_gpio_irq_init(g_key_operate[key_config->channel].pin_num, &key_gpio_cfg);
// }

/**
 * @brief
 *
 * @param args
 * @return VOID_T
 */
VOID_T app_key_push_timer_cb(VOID_T *args)
{
  TUYA_GPIO_NUM_E pin_num = *(TUYA_GPIO_NUM_E *)args;
  TAL_PR_NOTICE("pin:%d irq", pin_num);
  for (UINT8_T i = 0; i < g_key_sum; ++i)
  {
    if (pin_num == g_key_operate[i].pin_num)
    {
      g_key_operate[i].count = 0;
      tal_sw_timer_start(*g_key_operate[i].timer, g_debounce_time, TAL_TIMER_ONCE);
      break;
    }
  }
}

VOID_T app_ext_key_push_timer_cb(VOID_T *args)
{
  TUYA_GPIO_NUM_E pin_num = *(TUYA_GPIO_NUM_E *)args;
  TAL_PR_NOTICE("pin:%d irq", pin_num);
  if (pin_num == g_key_operate[g_key_sum].pin_num)
  {
    g_key_operate[g_key_sum].count = 0;
    tal_sw_timer_start(*g_key_operate[g_key_sum].timer, g_debounce_time, TAL_TIMER_ONCE);
  }
}

/**
 * @brief
 *
 * @param timer_id
 * @param arg
 * @return VOID_T
 */
// VOID_T app_button_scan_cb(TIMER_ID timer_id, VOID_T* arg)
// {
//     key_operate_t* key_operate = (key_operate_t*)arg;

//     TUYA_GPIO_LEVEL_E key_level = TUYA_GPIO_LEVEL_HIGH;
//     if (OPRT_OK != tal_gpio_read(key_operate->pin_num, &key_level)) {
//         return;
//     }
// TAL_PR_NOTICE("(TUYA_GPIO_LEVEL_E)key_operate->pin_irq_mode : %d key_level %d ", (TUYA_GPIO_LEVEL_E)key_operate->pin_irq_mode, key_level);
//     if (key_level == (TUYA_GPIO_LEVEL_E)key_operate->pin_irq_mode) {
//         g_key_func(key_operate->key_index, KEY_ST_RELEASE, key_operate->count * 20);
//         key_operate->count = 0;
//     } else {
//         g_key_func(key_operate->key_index, KEY_ST_PUSH, key_operate->count * 20);
//         key_operate->count++;
//         tal_sw_timer_start(*key_operate->timer, 20, TAL_TIMER_ONCE);
//     }
// }

VOID_T app_button_scan_cb(TIMER_ID timer_id, VOID_T *arg)
{
  key_operate_t *key_operate = (key_operate_t *)arg;

  TUYA_GPIO_LEVEL_E key_level = TUYA_GPIO_LEVEL_HIGH;
  if (OPRT_OK != tal_gpio_read(key_operate->pin_num, &key_level))
  {
    return;
  }

  TAL_PR_NOTICE("pin_irq_mode: %d, key_level: %d", key_operate->pin_irq_mode, key_level);

  // ˫شݵǰƽжϰ״̬
  if (key_operate->pin_irq_mode == TUYA_GPIO_IRQ_RISE_FALL)
  {
    // ˫شģʽ
    // if (key_level == TUYA_GPIO_LEVEL_LOW) {
    //     // ͵ƽʾ
    g_key_func(key_operate->key_index, KEY_ST_PUSH, key_operate->count * 20);
    key_operate->count++;
    tal_sw_timer_start(*key_operate->timer, 20, TAL_TIMER_ONCE);
    // } else {
    //     // ߵƽʾͷ
    //     g_key_func(key_operate->key_index, KEY_ST_RELEASE, key_operate->count * 20);
    //     // key_operate->count = 0;
    //     key_operate->count++;
    //     tal_sw_timer_start(*key_operate->timer, 20, TAL_TIMER_ONCE);
    // }
  }
  else
  {
    // شģʽԭ߼
    if (key_level == (TUYA_GPIO_LEVEL_E)key_operate->pin_irq_mode)
    {
      g_key_func(key_operate->key_index, KEY_ST_RELEASE, key_operate->count * 20);
      key_operate->count = 0;
    }
    else
    {
      g_key_func(key_operate->key_index, KEY_ST_PUSH, key_operate->count * 20);
      key_operate->count++;
      tal_sw_timer_start(*key_operate->timer, 20, TAL_TIMER_ONCE);
    }
  }
}